import math

import networkx as nx
import numpy as np
from matplotlib import pyplot as plt
from python.lib import json

from DHTOA1 import load_traffic_data, process_traffic_scenario, calculate_total_delay, semi_calculate_static_latency
from calculate_optical_delay import calculate_communication_delay
from electric_path_algo import allocate_paths, widest_path
from find_min_max_delay_path import optimize_reconfiguration, find_min_max_delay_path
from find_min_max_delay_path_test import matrix_to_communication_pairs
from topo1 import build_hybrid_topology_shared_tor,visualize_topology
from switchesalgo import allocate_switches_with_es


topo1=build_hybrid_topology_shared_tor(num_tor=4)
topo2=build_hybrid_topology_shared_tor(num_tor=16)
topo3=build_hybrid_topology_shared_tor(num_tor=32)

print("=============测试==================")
# 获取拓扑中所有链路的容量
for edge in topo1.edges():
    print(f"链路 {edge}: 容量 {topo1.edges[edge]['capacity']}")
print("=============测试==================")


# 输出topo1节点的信息
# print("topo2节点的信息：")
# for node in topo3.nodes():
#     print(node)
#
# # 定义一个函数来可视化拓扑
# # 定义一个函数来可视化拓扑
# visualize_topology(topo3)

# 获取流量信息
print("=======================计算小型拓扑的时延========================")

# 加载流量数据
with open("traffic_matrices.json",'r') as f:
    traffic_matrices = json.load(f)
 # 提取不同节点数量下的 all_to_all 流量矩阵
all_to_all_4 = traffic_matrices['4_nodes']['all_to_all']

burst_traffic_4= traffic_matrices['4_nodes']['burst_traffic']
all_to_all_burst_4= traffic_matrices['4_nodes']['all_to_all_burst']

# print("========测试=============")
# print(all_to_all_burst_4)
# print(type(all_to_all_burst_4))
# print("========测试=============")
# 处理基础流量，获得基础路径和流量字典

print("=============测试1==================")
# 获取拓扑中所有链路的容量
for edge in topo1.edges():
    print(f"链路 {edge}: 容量 {topo1.edges[edge]['capacity']}")
print("=============测试1==================")

base_paths, base_traffic = process_traffic_scenario(
        topo1,
        all_to_all_4,
        {
            'tor_nodes': {"ToR1", "ToR2", "ToR3", "ToR4"},
            'os_nodes': {"os1", "os2", "os3", "os4"},
            'threshold': 18
        }
    )
for path, traffic in base_paths.items():
    print(f"基础路径 {path}: 流量 {traffic}")

print("=============测试2==================")
# 获取拓扑中所有链路的容量
for edge in topo1.edges():
    print(f"链路 {edge}: 容量 {topo1.edges[edge]['capacity']}")
print("=============测试2==================")

hybrid_paths, hybrid_traffic = process_traffic_scenario(
        topo1,
        all_to_all_burst_4,
        {
            'tor_nodes': {"ToR1", "ToR2", "ToR3", "ToR4"},
            'os_nodes': {"os1", "os2", "os3", "os4"},
            'threshold': 40
        }
    )
for path, traffic in hybrid_paths.items():
    print(f"混合路径 {path}: 流量 {traffic}")

print("=============测试3==================")
# 获取拓扑中所有链路的容量
for edge in topo1.edges():
    print(f"链路 {edge}: 容量 {topo1.edges[edge]['capacity']}")
print("=============测试3==================")



# print("=============测试2==================")
# # 获取拓扑中所有链路的容量
# for edge in topo1.edges():
#     print(f"链路 {edge}: 容量 {topo1.edges[edge]['capacity']}")
# print("=============测试2==================")

print("=======================计算小型拓扑的时延========================")


print("==============获取半更新算法的时延===================")
# 获取半更新算法的时延
# max_semi_delay = semi_calculate_static_latency(hybrid_paths, recon_paths, static_delays, recon_delays, hybrid_traffic,
#                                         optical_capacity=200, verbose=True)
#
# print(f"半更新系统总的最大时延: {max_semi_delay:.2f} ms")

# 获取基础路径中走电网络通信对
# 初始化光网络和电网络通信对和路径为字典类型
# 转换为字典结构
# all_to_all_burst_4_dict = {
#     (f"ToR{i+1}", f"ToR{j+1}"): all_to_all_burst_4[i][j]
#     for i in range(4) for j in range(4)
#     if all_to_all_burst_4[i][j] > 0
# }


optical_pairs = {}
electric_pairs = {}

for pair, path in base_paths.items():
    print(f"\n正在分析通信对 {pair}: 完整路径 {path}")
    has_optical = False

    # 遍历路径中的所有链路
    for i in range(len(path) - 1):
        u = path[i]
        v = path[i + 1]

        # 获取链路类型（需要确保拓扑变量名称正确，这里假设是G）
        if topo1.has_edge(u, v):
            link_data = topo1.get_edge_data(u, v)
            link_type = link_data.get('type', 'unknown')  # 添加默认值防止KeyError

            print(f"链路 {u}->{v} 类型: {link_type}")

            if link_type == 'optical':
                has_optical = True
                # 只要存在光链路就归类为光网络通信对
                break  # 发现光链路后即可停止检查

    # 分类存储结果
    if has_optical:
        optical_pairs[pair] = path
    else:
        electric_pairs[pair] = path

# 打印光网络通信对
print("\n光网络通信对:")
for pair, path in optical_pairs.items():  # 使用.items()遍历字典
    print(f"通信对 {pair}:")
    print("完整路径:", " → ".join(path))  # 用箭头符号美化路径显示

# 打印电网络通信对
print("\n电网络通信对:")
for pair, path in electric_pairs.items():
    print(f"通信对 {pair}:")
    print("完整路径:", " → ".join(path))

# 光网络通信对的路由为静态的，电网络的路由需要动态更新，输出更新后通信对的路径

# 将list转为矩阵形式
all_to_all_burst_4_matrix = np.array(all_to_all_burst_4)
all_to_all_burst_4_dict = matrix_to_communication_pairs(all_to_all_burst_4_matrix, node_prefix="ToR")
# print("===========测试==============")
# print("转形式")
# print(all_to_all_burst_4_dict)
# print("===========测试==============")

# 初始化路由表
static_routing_table = optical_pairs.copy()  # 光网络路由表（静态）
# dynamic_routing_table = {}  # 电网络路由表（动态）


def update_electric_routing(network_topology, electric_pairs):
    """动态更新电网络路由"""
    # updated_routes = {}
    electric_pairs_traffic={}
    # # 遍历所有电网络通信对
    for pair in electric_pairs:
        source, destination = pair
        # 获取该通信对的流量需求
        traffic = all_to_all_burst_4_dict[pair]
        # 将通信对和流量需求存入字典
        electric_pairs_traffic[pair] = traffic
        print(f"\n正在更新电网络路由: {source} → {destination},流量需求为{traffic}")
    # 按照流量需求进行排序
    sorted_pairs = sorted(electric_pairs_traffic.items(), key=lambda x: x[1], reverse=True)

    allocation_results = allocate_paths(network_topology, sorted_pairs)

    # 输出排序后的通信对
    for pair, traffic in sorted_pairs:
        source, destination = pair
        print(f"{source} → {destination}: 流量需求为{traffic}")
    # # 基于最大流量原则为电网路由进行更新
    # for pair, traffic in sorted_pairs:
    #     source, destination = pair
    #     path = find_min_max_delay_path(topo1, source, destination, traffic)
    #     if path is not None:
    #         updated_routes[pair] = path
    #         print(f"{source} → {destination}: 路由更新为 {path}")
    #     else:
    #         print(f"{source} → {destination}: 无可用路径")
    #         updated_routes[pair] = None
    #         continue

    return allocation_results


# 首次动态路由计算（模拟网络状态更新）
print("============== 初始路由状态 ==============")
# 计算光网络通信对的路径延迟
for pair, path in optical_pairs.items():
    # 遍历path中的每条链路
    for i in range(len(path) - 1):
        u, v = path[i], path[i + 1]
        # 获取链路类型（需要确保拓扑变量名称正确，这里假设是G）
        if topo1.has_edge(u, v):
            link_data = topo1.get_edge_data(u, v)
            link_type = link_data.get('type', 'unknown')  # 添加默认值防止KeyError
# 更新电网络通信对的路径和计算更新路径之后的延迟
dynamic_routing_table = update_electric_routing(topo1, electric_pairs)
print("输出dynamic_routing_table：",dynamic_routing_table)
# 计算光网络通信对的延迟
for pair,path in optical_pairs:
    # 遍历path中的每条链路
    for i in range(len(path) - 1):
        u, v = path[i], path[i + 1]
        # 获取链路类型（需要确保拓扑变量名称正确，这里假设是G）
        if topo1.has_edge(u, v):
            link_data = topo1.get_edge_data(u, v)
            link_type = link_data.get('type', 'unknown')  # 添加默认值防止KeyError
            # print(f"链路 {u}->{v} 类型: {link_type}")

# 输出光网络路由的延迟
optical_delay = calculate_communication_delay(topo1, optical_pairs, all_to_all_burst_4_dict)
# 打印结果
print("半更新路由算法的光网络通信对延迟")
for pair, delay in optical_delay.items():
    src, dst = pair
    path = optical_pairs[pair]
    demand = all_to_all_burst_4_dict[pair]

    if not math.isfinite(delay):
        print(f"通信对 {src}→{dst} 路径无效")
        continue

    print(f"通信对: {src} → {dst}")
    print(f"路径: {' → '.join(path)}")
    print(f"流量需求: {demand}Gbps")
    print(f"总延迟: {delay} 秒")
    print("-" * 40)

# # 模拟网络变化：降低tor1-agg1链路带宽
# print("\n============== 模拟网络变化 ==============")
# G.edges[('tor1', 'agg1')]['capacity'] = 5  # 带宽降为5Gbps
# dynamic_routing_table = update_electric_routing(G, electric_pairs)

# 整合最终路由表
# final_routing_table = {**static_routing_table,  ** dynamic_routing_table}

# 可视化输出
# print("\n============== 最终路由表 ==============")
# print("【光网络静态路由】")
# for pair, path in static_routing_table.items():
#     print(f"{pair[0]} → {pair[1]}: {' → '.join(path)}")
#
# print("\n【电网络动态路由】")
# for pair, path in dynamic_routing_table.items():
#     print(f"{pair[0]} → {pair[1]}: {path}")


# 计算全更新拓扑的最大延迟
print("==============计算全更新拓扑的最大延迟===================")
# 优化重构路径
recon_paths, recon_delays, static_delays = optimize_reconfiguration(
    hybrid_traffic, topo1, base_paths, hybrid_paths
)

# print("======================测试===============")
# for static_delay in static_delays.values():
#     print(f"静态时延: {static_delay:.2f} ms")
#
# print("======================测试===============")

print("=============测试4==================")
# 获取拓扑中所有链路的容量
for edge in topo1.edges():
    print(f"链路 {edge}: 容量 {topo1.edges[edge]['capacity']}")
print("=============测试4==================")

print("\n优化重构路径的结果如下：")
print(f"需要重构的通信对: {len(recon_paths)} 条")
for pair, path in recon_paths.items():
    if path is not None:
        print(f"{pair}: 电网络路径 {path}，最大时延 {recon_delays[pair]:.2f} ms")
    else:
        print(f"{pair}：无可用路径")

# 输出不需要重构的通信对
print(f"无需重构的通信对：{len(hybrid_paths) - len(recon_paths)}")
for pair,path in hybrid_paths.items():
    if pair not in recon_paths:
        if path is not None:
            print(f"{pair}: 网络路径 {path}，最大时延 {static_delays[pair]:.2f} ms")
        else:
            print(f"{pair}：无可用路径")
            continue
max_delay = calculate_total_delay(hybrid_paths, recon_paths, static_delays, recon_delays, hybrid_traffic,
                              optical_reconstruction_delay=1, optical_capacity=200, verbose=True)
print("全更新算法的通信对的延迟")
print(f"\n光电混合更新系统总的最大时延: {max_delay:.2f} ms")


